package com.mano.demo;

import java.util.Collection;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * @Author: zj
 * @Description:
 * @Date: Created in 16:29 2020/9/7
 * @Modified By:
 */
public class ConsistentHashDemo<T> {

    private final HashFunction hashFunction;   // hash 算法
    private final int numbersOfReplicas;   // 虚拟节点数目
    private final SortedMap<Integer,T> circle = new TreeMap<Integer, T>();

    public ConsistentHashDemo(HashFunction hashFunction, int numbersOfReplicas, Collection<T> nodes){
        this.hashFunction = hashFunction;
        this.numbersOfReplicas = numbersOfReplicas;
        for(T node:nodes){
            add(node);
        }
    }

    public void add(T node){
        for (int i = 0; i < numbersOfReplicas ; i++) {
            circle.put(hashFunction.hash(node.toString()+i),node);
        }
    }

    public void remove(T node){
        for (int i = 0; i < numbersOfReplicas; i++) {
            circle.remove(hashFunction.hash(node.toString()+i));
        }

    }

    public T get(Object key){
        if(circle.isEmpty()){
            return null;
        }

        //得到该key的hash值
        int hash = hashFunction.hash((String) key);

        if(!circle.containsKey(hash)){
            //得到大于该Hash值的所有Map
            SortedMap<Integer, T> subMap = circle.tailMap(hash);
            if(subMap.isEmpty()){
                //如果没有比该key的hash值大的，则从第一个node开始
                Integer integer = circle.firstKey();
                return circle.get(integer);
            }else{
                //第一个Key就是顺时针过去离node最近的那个结点
                Integer integer = subMap.firstKey();
                return subMap.get(integer);
            }
        }

        return null;
    }


    @FunctionalInterface
    public interface HashFunction{
        int hash(String key);
    }

    public static void main(String[] args) {

        HashFunction hashFunction = (str) -> {
            final int p = 16777619;
            int hash = (int) 2166136261L;
            for (int i = 0; i < str.length(); i++)
                hash = (hash ^ str.charAt(i)) * p;
            hash += hash << 13;
            hash ^= hash >> 7;
            hash += hash << 3;
            hash ^= hash >> 17;
            hash += hash << 5;

            // 如果算出来的值为负数则取其绝对值
            if (hash < 0)
                hash = Math.abs(hash);
            return hash;

        };


    }


}
